package com.zlc.common.util;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.util.ObjectUtils;

import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;


/**
 * LocalDate 工具类
 */
public class LocalDateUtils {
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
    private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
    private static final DateTimeFormatter YEAR_FORMATTER = DateTimeFormatter.ofPattern("yyyy");

    private LocalDateUtils(){}

    /**
     * 获取当前系统总时间 秒数
     */
    public static long getTimeSeconds(LocalDateTime dateTime){
        return dateTime.toEpochSecond(ZoneOffset.of("+8"));
    }

    /**
     * 获取当前系统总时间 毫秒数
     */
    public static long getTimeMills(LocalDateTime dateTime){
        return dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    /**
     * 获取当前日期
     */
    public static LocalDate getNowDate(){
        return LocalDate.now();
    }

    /**
     * 获取当前时间
     */
    public static LocalDateTime getNowTime(){
        return LocalDateTime.now();
    }

    /**
     * 获取当前时间字符串
     */
    public static String getNowDateTimeStr(){
        LocalDateTime now = getNowTime();
        return now.format(DATE_TIME_FORMATTER);
    }

    /**
     * 获取当前日期字符串
     */
    public static String getNowDateStr(){
        LocalDate date = getNowDate();
        return date.format(DATE_FORMATTER);
    }

    public static String getNowStr(String pattern){
        if (!ObjectUtils.isEmpty(pattern)) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            LocalDateTime now = getNowTime();
            return now.format(formatter);
        }
        return getNowDateTimeStr();
    }

    public static LocalDateTime tranDateTime(LocalDate localDate){
        return LocalDateTime.of(localDate, LocalTime.of(0,0,0));
    }



    /**
     * 时间字符串转换成LocalDateTime
     */
    public static LocalDateTime parseDateTime(String date){
        return LocalDateTime.parse(date,DATE_TIME_FORMATTER);
    }

    /**
     * 时间字符串转换成LocalDateTime
     */
    public static LocalDateTime  parseDateTime(String date,String pattern){
        if(!ObjectUtils.isEmpty(pattern)){
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return LocalDateTime.parse(date,formatter);
        }
        return LocalDateTime.parse(date,DATE_TIME_FORMATTER);
    }

    public static LocalDateTime parseDateTimes(String date,String...patterns){
        if(ObjectUtils.isEmpty(patterns) || patterns[0] == null){
            return null;
        }
        Throwable t = null;
        for(String pattern : patterns){
            try {
                return parseDateTime(date, pattern);
            }catch (Exception e){
                t = e;
            }
        }
        throw new RuntimeException(t);
    }


    /**
     * 日期字符串转换成日期
     */
    public static LocalDate parseDate(String date){
        return LocalDate.parse(date,DATE_FORMATTER);
    }

    /**
     * 时间转换成字符串
     */
    public static String toDateStr(LocalDateTime dateTime){
        return dateTime.format(DATE_TIME_FORMATTER);
    }

    /**
     * 时间转换成字符串 指定pattern
     */
    public static String toDateStr(LocalDateTime dateTime,String pattern){
        if(!ObjectUtils.isEmpty(pattern)){
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return dateTime.format(formatter);
        }
        return dateTime.format(DATE_TIME_FORMATTER);
    }


    public static String  toDateStr(LocalDate date){
        return date.format(DATE_FORMATTER);
    }

    /**
     * 日期转换成字符串 指定pattern
     */
    public static String toDateStr(LocalDate date ,String pattern){
        if (!ObjectUtils.isEmpty(pattern)) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return date.format(formatter);
        }
        return date.format(DATE_FORMATTER);
    }

    public static String toDateStr(LocalTime time){
        return time.format(TIME_FORMATTER);
    }

    public static String toDateStr(LocalTime time,String pattern){
        if(!ObjectUtils.isEmpty(pattern)){
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return time.format(formatter);
        }
        return time.format(TIME_FORMATTER);
    }


    /**
     * 获取指定时间的所属月份的开始日期  字符串
     */
    public static String getMonthStartStr(LocalDateTime dateTime){
        String dateStr = dateTime.format(MONTH_FORMATTER);
        return dateStr + "-01 00:00:00";
    }

    /**
     * 获取指定时间的所属月份的开始日期  字符串，指定pattern
     */
    public static String getMonthStartStr(LocalDateTime dateTime,String pattern){
        if (!ObjectUtils.isEmpty(pattern)) {
            LocalDateTime startTime = getMonthStartTime(dateTime);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return startTime.format(formatter);
        }
        return getMonthStartStr(dateTime);
    }

    /**
     * 获取指定时间的所属月份的开始日期
     */
    public static LocalDateTime getMonthStartTime(LocalDateTime dateTime){
        String dateStr = getMonthStartStr(dateTime);
        return LocalDateTime.parse(dateStr,DATE_TIME_FORMATTER);
    }

    /**
     * 获取指定日期的所属月份的第一天
     */
    public static LocalDate getMonthStartDate(LocalDate date){
        String dateStr = date.format(MONTH_FORMATTER);
        return LocalDate.parse(dateStr+"-01",DATE_FORMATTER);
    }



    /**
     * 获取指定时间的所属月份的结束日期  字符串
     */
    public static String getMonthEndStr(LocalDateTime dateTime){
        Month month = dateTime.getMonth();
        int length = month.maxLength();
        String monthStr = dateTime.format(MONTH_FORMATTER);
        return monthStr + "-" + length +" 23:59:59";
    }

    /**
     * 获取指定时间的所属月份的结束日期  字符串  指定pattern
     */
    public static String getMonthEndStr(LocalDateTime dateTime,String pattern){
        if (!ObjectUtils.isEmpty(pattern)) {
            LocalDateTime endTime = getMonthEndTime(dateTime);
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return endTime.format(formatter);
        }
        return getMonthEndStr(dateTime);
    }

    /**
     * 获取指定时间的所属月份的结束日期
     */
    public static LocalDateTime getMonthEndTime(LocalDateTime dateTime){
        String dateStr = getMonthEndStr(dateTime);
        return LocalDateTime.parse(dateStr,DATE_TIME_FORMATTER);
    }


    /**
     * 获取只当时间所属年份的开始时间 字符串
     *
     * dateTime  2020-12-02   返回  2020-01-01 00:00:00
     */
    public static String  getYearStartStr(LocalDateTime dateTime){
        String yearStr = dateTime.format(YEAR_FORMATTER);
        return yearStr + "-01-01 00:00:00";
    }

    public static LocalDateTime  getYearStartTime(LocalDateTime dateTime){
        String yearStartStr = getYearStartStr(dateTime);
        return LocalDateTime.parse(yearStartStr,DATE_TIME_FORMATTER);
    }



    /**
     * 获取只当时间所属年份的最后时间 字符串
     *
     * dateTime  2020-12-02   返回  2020-12-31 23:59:59
     */
    public static String getYearEndStr(LocalDateTime dateTime){
        String yearStr = dateTime.format(YEAR_FORMATTER);
        return yearStr + "-12-31 23:59:59";
    }

    public static LocalDateTime  getYearEndTime(LocalDateTime dateTime){
        String yearStartStr = getYearEndStr(dateTime);
        return LocalDateTime.parse(yearStartStr,DATE_TIME_FORMATTER);
    }


    /**
     * 获取指定日期的指定天数后的时间
     */
    public static LocalDateTime getNextDay(LocalDateTime dateTime,int day){
        return dateTime.plusDays(day);
    }

    public static String getNextDayStr(LocalDateTime dateTime,int day){
        LocalDateTime nextDay = getNextDay(dateTime,day);
        return toDateStr(nextDay);
    }

    public static LocalDate getNextDay(LocalDate date ,int day){
        return date.plusDays(day);
    }

    public static String getNextDayStr(LocalDate date,int day){
        LocalDate nextDay = getNextDay(date,day);
        return toDateStr(nextDay);
    }



    /**
     * 获取指定日期的指定天数后的时间
     */
    public static LocalDateTime getNextMonth(LocalDateTime dateTime,int month){
        return dateTime.plusMonths(month);
    }

    /**
     * 获取只当日期的指定天数前的时间
     */
    public static LocalDateTime getLastDay(LocalDateTime dateTime,int day){
        return dateTime.plusDays(-day);
    }

    public static LocalDate getLastDay(LocalDate date,int day){
        return date.plusDays(-day);
    }

    /**
     * 获取只当日期的指定天数前的时间 字符串
     */
    public static String getLastDayStr(LocalDateTime dateTime,int day){
        LocalDateTime lastDay =  dateTime.plusDays(-day);
        return toDateStr(lastDay);
    }

    public static String getLastDayStr(LocalDate date,int day){
        LocalDate lastDay =  date.plusDays(-day);
        return toDateStr(lastDay);
    }

    /**
     * 获取两个时间之间的秒数
     */
    public static long getBetweenSecondsNumber(LocalDateTime start,LocalDateTime end){
        Long startSeconds = getTimeSeconds(start);
        Long endSeconds = getTimeSeconds(end);
        return endSeconds - startSeconds;
    }


    /**
     * 获取两个时间之间的分钟数数
     */
    public static long getBetweenMinuteNumber(LocalDateTime start,LocalDateTime end){
        Long startSeconds = getTimeSeconds(start);
        Long endSeconds = getTimeSeconds(end);
        return ((endSeconds - startSeconds) / (60));
    }


    /**
     * 获取两个时间之间的小时数
     */
    public static int getBetweenHourNumber(LocalDateTime start,LocalDateTime end){
        Long startSeconds = getTimeSeconds(start);
        Long endSeconds = getTimeSeconds(end);
        return (int)((endSeconds - startSeconds) / (60 * 60));
    }

    /**
     * 获取两个时间之间的天数
     */
    public static int getBetweenDayNumber(LocalDateTime start,LocalDateTime end){
        Long startSeconds = getTimeSeconds(start);
        Long endSeconds = getTimeSeconds(end);
        return (int)((endSeconds - startSeconds) / (24 * 60 * 60));
    }

    /**
     * 获取两个时间之间的周数
     */
    public static int getBetweenWeekNumber(LocalDateTime start,LocalDateTime end){
        Long startSeconds = getTimeSeconds(start);
        Long endSeconds = getTimeSeconds(end);
        return (int)((endSeconds - startSeconds) / (7 * 24 * 60 * 60));
    }

    /**
     * 获取两个时间之间的月数 按照每月30天计算
     */
    public static int getBetweenMonthNumber(LocalDateTime start, LocalDateTime end){
        return getBetweenMonths(start.toLocalDate(),end.toLocalDate()).size();
    }


    /**
     * 获取两个时间之间的年数  按照每年365天计算
     */
    public static int getBetweenYearNumber(LocalDateTime start,LocalDateTime end){
        Long startSeconds = getTimeSeconds(start);
        Long endSeconds = getTimeSeconds(end);
        return (int)((endSeconds - startSeconds) / (365 * 24 * 60 * 60));
    }

    /**
     * 获取两个时间之间的所有日期
     */
    public static List<LocalDate>  getBetweenDates(LocalDate start,LocalDate end){
        if(end.isBefore(start)){
            return Collections.emptyList();
        }
        List<LocalDate> dates = new ArrayList<>();
        while(start.isBefore(end)){
            dates.add(start);
            start = getNextDay(start,1);
        }
        dates.add(end);
        return dates;
    }

    /**
     * 获取两个时间之间的所有日期 字符串
     */
    public static List<String> getBetweenDateStrs(LocalDate start,LocalDate end){
        if(end.isBefore(start)){
            return Collections.emptyList();
        }
        List<String> dates = new ArrayList<>();
        while(start.isBefore(end)){
            dates.add(toDateStr(start));
            start = getNextDay(start,1);
        }
        dates.add(toDateStr(end));
        return dates;
    }


    /**
     * 获取两个日期之间的所有月份，取月的第一天
     */
    public static List<LocalDate> getBetweenMonths(LocalDate start,LocalDate end){
        if(end.isBefore(start)){
            return Collections.emptyList();
        }
        List<LocalDate> dates = new ArrayList<>();
        while(start.isBefore(end)){
            LocalDate date = getMonthStartDate(start);
            dates.add(date);
            start = date.plusMonths(1);
        }
        return dates;
    }


    /**
     * 获取两个时间之间的所有月份 字符串
     */
    public static List<String> getBetweenMonthStrs(LocalDate start,LocalDate end){
        if(end.isBefore(start)){
            return Collections.emptyList();
        }
        List<String> dates = new ArrayList<>();
        while(start.isBefore(end)){
            LocalDate date = getMonthStartDate(start);
            dates.add(toDateStr(date));
            start = date.plusMonths(1);
        }
        return dates;
    }

    /**
     * 获取两个日期之间有多少个工作日，仅排除周末，不包含节假日
     */
    public static List<LocalDate> getWorkDates(LocalDate start,LocalDate end){
        if(end.isBefore(start)){
            return Collections.emptyList();
        }
        List<LocalDate> dates = new ArrayList<>();
        while (start.isBefore(end) || start.compareTo(end) == 0) {
            DayOfWeek week = start.getDayOfWeek();
            if(week.getValue() != 6 && week.getValue() != 7){
                dates.add(start);
            }
            start = getNextDay(start,1);
        }

        return dates;
    }

    /**
     * 获取两个日期之间有多少个工作日，仅排除周末，不包含节假日  字符串
     */
    public static List<String> getWorkDateStrs(LocalDate start, LocalDate end){
        if(end.isBefore(start)){
            return Collections.emptyList();
        }
        List<String> dates = new ArrayList<>();
        while (start.isBefore(end) || start.compareTo(end) == 0) {
            DayOfWeek week = start.getDayOfWeek();
            if(week.getValue() != 6 && week.getValue() != 7){
                dates.add(toDateStr(start));
            }
            start = getNextDay(start,1);
        }

        return dates;
    }

    /**
     * 获取两个日期之间有多少个工作日天数
     */
    public static int getWorkDateNumber(LocalDate start,LocalDate end){
        return getWorkDates(start,end).size();
    }


    public static LocalDateTime dateToLocalDateTime(Date date){
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        return instant.atZone(zoneId).toLocalDateTime();
    }
    public static LocalDateTime getDateEnd(LocalDateTime dateTime){
        return  LocalDateTime.of(dateTime.getYear(),dateTime.getMonth(),dateTime.getDayOfMonth(),23,59,59);
    }


}
